{
 "cells": [
  {
   "cell_type": "raw",
   "id": "3243cb05-8243-421f-99fa-98201abb3094",
   "metadata": {},
   "source": [
    "---\n",
    "sidebar_position: 3\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14b94240",
   "metadata": {},
   "source": [
    "# Tool use without function calling\n",
    "\n",
    "In this guide we'll build a Chain that does not rely on any special model APIs (like function-calling, which we showed in the [Quickstart](/docs/use_cases/tool_use/quickstart)) and instead just prompts the model directly to invoke tools."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0a22cb8-19e7-450a-9d1b-6848d2c81cd1",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "We'll need to install the following packages:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8c556c5e-b785-428b-8e7d-efd34a2a1adb",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install --upgrade --quiet langchain langchain-openai"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e727d22-f861-4eee-882a-688f8efc885e",
   "metadata": {},
   "source": [
    "And set these environment variables:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "527ef906-0104-4872-b4e5-f371cf73feba",
   "metadata": {},
   "outputs": [],
   "source": [
    "import getpass\n",
    "import os\n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = getpass.getpass()\n",
    "\n",
    "# If you'd like to use LangSmith, uncomment the below:\n",
    "# os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
    "# os.environ[\"LANGCHAIN_API_KEY\"] = getpass.getpass()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68946881",
   "metadata": {},
   "source": [
    "## Create a tool\n",
    "\n",
    "First, we need to create a tool to call. For this example, we will create a custom tool from a function. For more information on all details related to creating custom tools, please see [this guide](/docs/modules/agents/tools/)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "90187d07",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.tools import tool\n",
    "\n",
    "\n",
    "@tool\n",
    "def multiply(first_int: int, second_int: int) -> int:\n",
    "    \"\"\"Multiply two integers together.\"\"\"\n",
    "    return first_int * second_int"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d7009e1a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "multiply\n",
      "multiply(first_int: int, second_int: int) -> int - Multiply two integers together.\n",
      "{'first_int': {'title': 'First Int', 'type': 'integer'}, 'second_int': {'title': 'Second Int', 'type': 'integer'}}\n"
     ]
    }
   ],
   "source": [
    "print(multiply.name)\n",
    "print(multiply.description)\n",
    "print(multiply.args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "be77e780",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "20"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "multiply.invoke({\"first_int\": 4, \"second_int\": 5})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15dd690e-e54d-4209-91a4-181f69a452ac",
   "metadata": {},
   "source": [
    "## Creating our prompt\n",
    "\n",
    "We'll want to write a prompt that specifies the tools the model has access to, the arguments to those tools, and the desired output format of the model. In this case we'll instruct it to output a JSON blob of the form `{\"name\": \"...\", \"arguments\": {...}}`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c64818f0-9364-423c-922e-bdfb8f01e726",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'multiply: multiply(first_int: int, second_int: int) -> int - Multiply two integers together.'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.tools.render import render_text_description\n",
    "\n",
    "rendered_tools = render_text_description([multiply])\n",
    "rendered_tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "63552d4d-8bd6-4aca-8805-56e236f6552d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "system_prompt = f\"\"\"You are an assistant that has access to the following set of tools. Here are the names and descriptions for each tool:\n",
    "\n",
    "{rendered_tools}\n",
    "\n",
    "Given the user input, return the name and input of the tool to use. Return your response as a JSON blob with 'name' and 'arguments' keys.\"\"\"\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [(\"system\", system_prompt), (\"user\", \"{input}\")]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14df2cd5-b6fa-4b10-892d-e8692c7931e5",
   "metadata": {},
   "source": [
    "## Adding an output parser\n",
    "\n",
    "We'll use the `JsonOutputParser` for parsing our models output to JSON."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f129f5bd-127c-4c95-8f34-8f437da7ca8f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': 'multiply', 'arguments': {'first_int': 13, 'second_int': 4}}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.output_parsers import JsonOutputParser\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)\n",
    "chain = prompt | model | JsonOutputParser()\n",
    "chain.invoke({\"input\": \"what's thirteen times 4\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e29dd4c-8eb5-457f-92d1-8add076404dc",
   "metadata": {},
   "source": [
    "## Invoking the tool\n",
    "\n",
    "We can invoke the tool as part of the chain by passing along the model-generated \"arguments\" to it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0555b384-fde6-4404-86e0-7ea199003d58",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "52"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from operator import itemgetter\n",
    "\n",
    "chain = prompt | model | JsonOutputParser() | itemgetter(\"arguments\") | multiply\n",
    "chain.invoke({\"input\": \"what's thirteen times 4\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d60b2cb-6ce0-48fc-8d18-d2337161a53d",
   "metadata": {},
   "source": [
    "## Choosing from multiple tools\n",
    "\n",
    "Suppose we have multiple tools we want the chain to be able to choose from:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "95c86d32-ee45-4c87-a28c-14eff19b49e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "@tool\n",
    "def add(first_int: int, second_int: int) -> int:\n",
    "    \"Add two integers.\"\n",
    "    return first_int + second_int\n",
    "\n",
    "\n",
    "@tool\n",
    "def exponentiate(base: int, exponent: int) -> int:\n",
    "    \"Exponentiate the base to the exponent power.\"\n",
    "    return base**exponent"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "748405ff-4c85-4bd7-82e1-30458b5a4106",
   "metadata": {},
   "source": [
    "With function calling, we can do this like so:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb3aa89e-40e1-45ec-b1f3-ab28cfc8e42d",
   "metadata": {},
   "source": [
    "If we want to run the model selected tool, we can do so using a function that returns the tool based on the model output. Specifically, our function will action return it's own subchain that gets the \"arguments\" part of the model output and passes it to the chosen tool:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "db254773-5b8e-43d0-aabe-c21566c154cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [add, exponentiate, multiply]\n",
    "\n",
    "\n",
    "def tool_chain(model_output):\n",
    "    tool_map = {tool.name: tool for tool in tools}\n",
    "    chosen_tool = tool_map[model_output[\"name\"]]\n",
    "    return itemgetter(\"arguments\") | chosen_tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "ad9f5cff-b86a-45fc-9ce4-b0aa9025a378",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1135"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rendered_tools = render_text_description(tools)\n",
    "system_prompt = f\"\"\"You are an assistant that has access to the following set of tools. Here are the names and descriptions for each tool:\n",
    "\n",
    "{rendered_tools}\n",
    "\n",
    "Given the user input, return the name and input of the tool to use. Return your response as a JSON blob with 'name' and 'arguments' keys.\"\"\"\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [(\"system\", system_prompt), (\"user\", \"{input}\")]\n",
    ")\n",
    "\n",
    "chain = prompt | model | JsonOutputParser() | tool_chain\n",
    "chain.invoke({\"input\": \"what's 3 plus 1132\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4a9c5aa-f60a-4017-af6f-1ff6e04bfb61",
   "metadata": {},
   "source": [
    "## Returning tool inputs\n",
    "\n",
    "It can be helpful to return not only tool outputs but also tool inputs. We can easily do this with LCEL by `RunnablePassthrough.assign`-ing the tool output. This will take whatever the input is to the RunnablePassrthrough components (assumed to be a dictionary) and add a key to it while still passing through everything that's currently in the input:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "45404406-859d-4caa-8b9d-5838162c80a0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': 'add',\n",
       " 'arguments': {'first_int': 3, 'second_int': 1132},\n",
       " 'output': 1135}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "\n",
    "chain = (\n",
    "    prompt | model | JsonOutputParser() | RunnablePassthrough.assign(output=tool_chain)\n",
    ")\n",
    "chain.invoke({\"input\": \"what's 3 plus 1132\"})"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "poetry-venv",
   "language": "python",
   "name": "poetry-venv"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
